/*!
    \copyright  Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
                All rights reserved.
                Confidential and Proprietary - Qualcomm Technologies, Inc.
\file       dfu_rules.c
    \ingroup    dfu
\brief      Rules for the DFU process
*/
#ifdef INCLUDE_DFU

#include "dfu_rules.h"
#include "rules_engine.h"
#include "dfu.h"
#include "dfu_peer.h"
#ifdef INCLUDE_TRANSPORT_LAYER_RELAY
#include "dfu_transport_relay.h"
#endif
#include "bt_device.h"
#include <upgrade_fw_if.h>
#include <logging.h>

/* Make the type used for message IDs available in debug tools */
LOGGING_PRESERVE_MESSAGE_ENUM(dfu_rules_messages_t)

/*! \{
    Macros for diagnostic output that can be suppressed. */

#define DFU_RULE_LOG         DEBUG_LOG_INFO
/*! \} */

/* Currently there is no rule set which runs with params. Hence this code is gaurded now.
 * Will be ungaurded once there is any usage
 */
#ifdef RUN_WITH_PARAM

/* Forward declaration for use in RULE_ACTION_RUN_PARAM macro below
*/
static rule_action_t dfuRules_CopyRunParams(const void* param, size_t size_param);

/*! \brief Macro used by rules to return RUN action with parameters to return.

    Copies the parameters/data into the rules instance where the rules engine
    can use it when building the action message.
*/
#define RULE_ACTION_RUN_PARAM(x)   dfuRules_CopyRunParams(&(x), sizeof(x))
#endif

dfu_rules_task_data_t dfu_rules_task_data;

/*! \{
    Rule function prototypes, so we can build the rule tables below. */

DEFINE_RULE(dfuRuleValidationComplete);
DEFINE_RULE(dfuRuleStartValidation);
DEFINE_RULE(dfuRuleRelayDataTransferComplete);
DEFINE_RULE(dfuRuleRelayResumePointInfo);
DEFINE_RULE(dfuRuleStartPeerDFU);
DEFINE_RULE(dfuRuleStartReboot);
DEFINE_RULE(dfuRuleResumePointMismatchCheck);
DEFINE_RULE(dfuRuleResumePointMismatchAbort);
DEFINE_RULE(dfuRulePostRebootMismatchInteractiveAbort);
DEFINE_RULE(dfuRulePostRebootMismatchSilentAbort);
DEFINE_RULE(dfuRuleRequestCommit);
#ifdef INCLUDE_DFU_PEER
DEFINE_RULE(dfuRuleCommitPeer);
#endif
DEFINE_RULE(dfuRuleCommitSelf);
#ifdef INCLUDE_TRANSPORT_LAYER_RELAY
DEFINE_RULE(dfuRuleStartTransportRelay);
#endif


/*! \} */

/*! \brief DFU process rules deciding behaviour.
*/
const rule_entry_t dfu_rules_set[] =
{
    RULE(DFU_EVENT_VALIDATION_COMPLETE,            dfuRuleValidationComplete,                DFU_RULES_VALIDATION_COMPLETE),
    RULE(DFU_EVENT_DATA_TRANSFER_COMPLETE,         dfuRuleStartValidation,                   DFU_RULES_START_VALIDATION),
    RULE(DFU_EVENT_DATA_TRANSFER_COMPLETE,         dfuRuleRelayDataTransferComplete,         DFU_RULES_RELAY_TRANSFER_COMPLETE),
    RULE(DFU_EVENT_PEER_END_DATA_TRANSFER,         dfuRuleStartValidation,                   DFU_RULES_START_VALIDATION),
    RULE(DFU_EVENT_UPGRADE_PEER_VLDTN_COMPLETE,    dfuRuleValidationComplete,                DFU_RULES_VALIDATION_COMPLETE),
    RULE(DFU_EVENT_RESUME_POINT_SYNC,              dfuRuleRelayResumePointInfo,              DFU_RULES_RELAY_RESUME_POINT_INFO),
    RULE(DFU_EVENT_RESUME_POINT_SYNC_COMPLETED,    dfuRuleStartValidation,                   DFU_RULES_START_VALIDATION),
    RULE(DFU_EVENT_RESUME_POINT_SYNC_COMPLETED,    dfuRuleValidationComplete,                DFU_RULES_VALIDATION_COMPLETE),
    RULE(DFU_EVENT_RESUME_POINT_SYNC_COMPLETED,    dfuRuleResumePointMismatchCheck,          DFU_RULES_RESUME_POINT_MISMATCH_CHECK),
    RULE(DFU_EVENT_RESUME_POINT_SYNC_COMPLETED,    dfuRuleResumePointMismatchAbort,          DFU_RULES_RESUME_POINT_MISMATCH_SILENT_ABORT),
    RULE(DFU_EVENT_RESUME_POINT_SYNC_COMPLETED,    dfuRulePostRebootMismatchInteractiveAbort,DFU_RULES_POST_REBOOT_RESUME_POINT_MISMATCH_ABORT),
    RULE(DFU_EVENT_RESUME_POINT_SYNC_COMPLETED,    dfuRulePostRebootMismatchSilentAbort,     DFU_RULES_RESUME_POINT_MISMATCH_SILENT_ABORT),
    
    RULE(DFU_EVENT_DFU_PEER_CONNECTED,             dfuRuleStartValidation,                   DFU_RULES_START_VALIDATION),
    RULE(DFU_EVENT_DFU_PEER_CONNECTED,             dfuRuleValidationComplete,                DFU_RULES_VALIDATION_COMPLETE),
    RULE(DFU_EVENT_DFU_PEER_CONNECTED,             dfuRuleResumePointMismatchCheck,          DFU_RULES_RESUME_POINT_MISMATCH_CHECK),
    RULE(DFU_EVENT_UPGRADE_START_DATA_IND,         dfuRuleStartPeerDFU,                      DFU_RULES_START_PEER_DFU),
    RULE(DFU_EVENT_RESUME_POINT_SYNC_COMPLETED,    dfuRuleStartPeerDFU,                      DFU_RULES_START_PEER_DFU),
    /* This event rule set is for starting the peer dfu during handover scenario once the dfu resumes on new primary. */
    RULE(DFU_EVENT_UPGRADE_RESUME,                 dfuRuleStartPeerDFU,                      DFU_RULES_START_PEER_DFU),
    RULE(DFU_EVENT_UPGRADE_RESUME,                 dfuRuleValidationComplete,                DFU_RULES_VALIDATION_COMPLETE),
    RULE(DFU_EVENT_UPGRADE_RESUME,                 dfuRuleStartValidation,                   DFU_RULES_START_VALIDATION),
    RULE(DFU_EVENT_UPGRADE_PEER_PROCESS_COMPLETE,  dfuRuleStartReboot,                       DFU_RULES_START_REBOOT),
    RULE(DFU_EVENT_UPGRADE_TRANSFER_COMPLETE_RES,  dfuRuleStartReboot,                       DFU_RULES_START_REBOOT),
    RULE(DFU_EVENT_PROCEED_TO_COMMIT_RCD,          dfuRuleRequestCommit,                     DFU_RULES_SEND_COMMIT_REQ),
    RULE(DFU_EVENT_PEER_COMMIT_REQ_IND,            dfuRuleRequestCommit,                     DFU_RULES_SEND_COMMIT_REQ),
    RULE(DFU_EVENT_PEER_HANDOVER_COMPLETE,         dfuRuleStartPeerDFU,                      DFU_RULES_START_PEER_DFU),
#ifdef INCLUDE_DFU_PEER
    RULE(DFU_EVENT_PEER_COMMIT_REQ_IND,            dfuRuleCommitPeer,               DFU_RULES_COMMIT_PEER),
    RULE(DFU_EVENT_UPGRADE_COMMIT_CFM,             dfuRuleCommitPeer,               DFU_RULES_COMMIT_PEER),
#endif
    RULE(DFU_EVENT_UPGRADE_COMMIT_CFM,             dfuRuleCommitSelf,               DFU_RULES_COMMIT_SELF),
    RULE(DFU_EVENT_UPGRADE_PEER_COMPLETE_IND,      dfuRuleCommitSelf,               DFU_RULES_COMMIT_SELF),
#ifdef INCLUDE_TRANSPORT_LAYER_RELAY
    RULE(DFU_EVENT_UPGRADE_OUTBAND_DATA_REQ,       dfuRuleStartTransportRelay,      DFU_RULES_START_TRANSPORT_RELAY_DATA_TRANSFER),
    RULE(DFU_EVENT_PEER_OUTBAND_DATA_REQ,          dfuRuleStartTransportRelay,      DFU_RULES_START_TRANSPORT_RELAY_DATA_TRANSFER),
#endif
};


/*****************************************************************************
 * RULES FUNCTIONS
 *****************************************************************************/

static rule_action_t dfuRuleResumePointMismatchAbort(void)
{
#ifdef INCLUDE_DFU_PEER
    if(UpgradeGetResumePoint() == UPGRADE_RESUME_POINT_PRE_REBOOT &&
        UpgradePeerGetResumePoint() == UPGRADE_RESUME_POINT_START)
        {
            DFU_RULE_LOG("dfuRuleResumePointMismatchAbort, allowed to run");
            return rule_action_run;
        }
#endif
        DFU_RULE_LOG("dfuRuleResumePointMismatchAbort, ignore as dfu rules not allowed to run");
        return rule_action_ignore;
}

static rule_action_t dfuRulePostRebootMismatchInteractiveAbort(void)
{
#ifdef INCLUDE_DFU_PEER
    bool is_silent_commit_enabled = Dfu_IsSilentCommitEnabled();
    if(!is_silent_commit_enabled && UpgradeGetResumePoint() == UPGRADE_RESUME_POINT_POST_REBOOT &&
        UpgradePeerGetResumePoint() == UPGRADE_RESUME_POINT_PRE_REBOOT)
        {
            DFU_RULE_LOG("dfuRulePostRebootMismatchInteractiveAbort, allowed to run as post reboot resume point mismatch");
            return rule_action_run;
        }
#endif
        DFU_RULE_LOG("dfuRulePostRebootMismatchInteractiveAbort, ignore as dfu rules not allowed to run");
        return rule_action_ignore;
}


static rule_action_t dfuRulePostRebootMismatchSilentAbort(void)
{
#ifdef INCLUDE_DFU_PEER
    bool is_silent_commit_enabled = Dfu_IsSilentCommitEnabled();
    if(is_silent_commit_enabled && UpgradeGetResumePoint() == UPGRADE_RESUME_POINT_POST_REBOOT &&
        UpgradePeerGetResumePoint() == UPGRADE_RESUME_POINT_PRE_REBOOT)
        {
            DFU_RULE_LOG("dfuRulePostRebootMismatchSilentAbort, allowed to run as resume point mismatch check during silent commit");
            return rule_action_run;
        }
#endif
        DFU_RULE_LOG("dfuRulePostRebootMismatchSilentAbort, ignore as dfu rules not allowed to run");
        return rule_action_ignore;
}

static rule_action_t dfuRuleResumePointMismatchCheck(void)
{
#ifdef INCLUDE_DFU_PEER
    if(UpgradeGetResumePoint() >= UPGRADE_RESUME_POINT_POST_REBOOT && UPGRADE_PEER_IS_CONNECTED 
        && UpgradePeerGetResumePoint() == UPGRADE_RESUME_POINT_START)
        {
            DFU_RULE_LOG("dfuRuleResumePointMismatchCheck, allowed to run");
            return rule_action_run;
        }
#endif
        DFU_RULE_LOG("dfuRuleResumePointMismatchCheck, ignore as dfu rules not allowed to run");
        return rule_action_ignore;
}

static rule_action_t dfuRuleRequestCommit(void)
{
    bool is_silent_commit_enabled = Dfu_IsSilentCommitEnabled();

#ifdef INCLUDE_DFU_PEER
    bool is_primary = BtDevice_IsMyAddressPrimary();
#endif

#ifdef INCLUDE_DFU_PEER
    /* Secondary EB*/
    if(!is_primary)
    {
        /*! Device needs to receive PROCEED_TO_COMMIT message before sending COMMIT_REQ.*/
        if(UpgradeStateIsCommitVerification())
        {
            DFU_RULE_LOG("dfuRuleRequestCommit, allowed to run on secondary device");
            return rule_action_run;
        }
    }
    /* Primary EB*/
    else
    {
        /*! For single earbud interactive commit, primary needs to receive
         * PROCEED_TO_COMMIT host message for sending COMMIT_REQ.*/
        if(!is_silent_commit_enabled && UpgradeStateIsCommitVerification() && UpgradeIsSingleDeviceDFUEnabled())
        {
            DFU_RULE_LOG("dfuRuleRequestCommit, allowed to run in interactive commit on single earbud");
            return rule_action_run;
        }
#ifdef INCLUDE_CROSS_VERSION_DFU
        if(!is_silent_commit_enabled && UpgradeStateIsCommitVerification() && UpgradeIsCrossVersionStatusLower())
        {
            DFU_RULE_LOG("dfuRuleRequestCommit, allowed to run as cross version is lower");
            return rule_action_run;
        }
#endif
        /*! For interactive dfu, primary should be connected to peer, secondary should have sent COMMIT_REQ to primary and 
         *  primary should have received PROCCEED_TO_COMMIT before sending COMMIT_REQ to host.*/
        if(UPGRADE_PEER_IS_CONNECTED && !is_silent_commit_enabled && UpgradeStateIsCommitVerification()
            && UpgradePeerStateIsCommitReqRcd() && !UpgradeIsSingleDeviceDFUEnabled())
        {
            DFU_RULE_LOG("dfuRuleRequestCommit, allowed to run in interactive commit");
            return rule_action_run;
        }
    }
#else
    /* Headset */
    /*! For interactive dfu, device should have received PROCCEED_TO_COMMIT before sending COMMIT_REQ to host. */
    if(!is_silent_commit_enabled && UpgradeStateIsCommitVerification())
    {
        DFU_RULE_LOG("dfuRuleRequestCommit, allowed to run");
        return rule_action_run;
    }
#endif

    DFU_RULE_LOG("dfuRuleRequestCommit, ignore as dfu rules not allowed to run");
    return rule_action_ignore;
}


static rule_action_t dfuRuleStartValidation(void)
{
    if (    
#ifdef INCLUDE_DFU_PEER
       (
#endif
        UpgradeIsResumePoinPreValidate() && UpgradeIsWaitForValidation()
#ifdef INCLUDE_DFU_PEER
        &&(( UPGRADE_PEER_IS_CONNECTED && UpgradePeerIsResumePointPreValidate())
        || (UpgradeIsCrossVersionStatusLower() || UpgradeIsSingleDeviceDFUEnabled())))
#endif
       )
    {
        DFU_RULE_LOG("dfuRuleStartValidation, allowed to run");
        return rule_action_run;
    }

    DFU_RULE_LOG("dfuRuleStartValidation, ignore as dfu rules not allowed to run");
    return rule_action_ignore;
}

static rule_action_t dfuRuleCommitSelf(void)
{
#ifdef INCLUDE_DFU_PEER
    bool is_silent_commit_enabled = Dfu_IsSilentCommitEnabled();
    bool is_primary = BtDevice_IsMyAddressPrimary();

    /* Secondary EB*/
    if(!is_primary)
    {
        /*! Secondary device needs to be received COMMIT_CFM
         * host message from primary for committing new image.*/
        if(UpgradeStateIsCommit())
        {
            DFU_RULE_LOG("dfuRuleCommitSelf, allowed to run on secondary");
            return rule_action_run;
        }
    }
    /* Primary EB*/
    else
    {
        /*! For single earbud dfu, COMMIT_CFM host message should be received before committing image. */
        if(!is_silent_commit_enabled && UpgradeIsSingleDeviceDFUEnabled() && UpgradeStateIsCommit())
        {
            DFU_RULE_LOG("dfuRuleCommitSelf, allowed to run single earbud dfu interactive commit.");
            return rule_action_run;
        }
#ifdef INCLUDE_CROSS_VERSION_DFU
        if(!is_silent_commit_enabled && UpgradeStateIsCommit() && UpgradeIsCrossVersionStatusLower())
        {
            DFU_RULE_LOG("dfuRuleCommitSelf, allowed to run as cross version is lower");
            return rule_action_run;
        }
#endif
        /*! For interactive dfu, COMMIT_CFM host message needs to be received from host and 
         *  COMPLETE_IND from secondary before committing image.*/
        if(!is_silent_commit_enabled && !UpgradeIsSingleDeviceDFUEnabled()
            && UPGRADE_PEER_IS_CONNECTED && UpgradePeerStateIsComplete() && UpgradeStateIsCommit())
        {
            DFU_RULE_LOG("dfuRuleCommitSelf, allowed to run earbud dfu interactive commit");
            return rule_action_run;
        }
        /*! For Silent commit, primary does not receive any host message upgrade SM state will be in COMMIT_HOST_CONTINUE state.
         *  Primary should have received COMPLETE_IND from secondary, before committing. */
        if(is_silent_commit_enabled && UPGRADE_PEER_IS_CONNECTED && UpgradePeerStateIsComplete())
        {
            DFU_RULE_LOG("dfuRuleCommitSelf, allowed to run in silent commit on primary");
            return rule_action_run;
        }
    }
#else
    /* Headset */
    /*! Device needs to receive COMMIT_CFM host message for committing image.*/
    if(UpgradeStateIsCommit())
    {
        DFU_RULE_LOG("dfuRuleCommitSelf, allowed to run for headset dfu interactive commit");
        return rule_action_run;
    }
#endif

    DFU_RULE_LOG("dfuRuleCommitSelf, ignore as dfu rules not allowed to run");
    return rule_action_ignore;
}

static rule_action_t dfuRuleValidationComplete(void)
{
    if(     
#ifdef INCLUDE_DFU_PEER
      (
#endif
       UpgradeIsValidationComplete()
#ifdef INCLUDE_DFU_PEER
       && ((UPGRADE_PEER_IS_CONNECTED && UpgradePeerIsVldtnComplete())
       || (UpgradeIsCrossVersionStatusLower() || UpgradeIsSingleDeviceDFUEnabled())))
#endif
      )
    {
        DFU_RULE_LOG("dfuRuleValidationComplete, allowed to run");
        return rule_action_run;
    }

    DFU_RULE_LOG("dfuRuleValidationComplete, ignore as dfu rules not allowed to run");
    return rule_action_ignore;

}

static rule_action_t dfuRuleRelayDataTransferComplete(void)
{
#ifdef INCLUDE_DFU_PEER
    if(BtDevice_IsMyAddressPrimary() && UPGRADE_PEER_IS_CONNECTED)
    {
        DFU_RULE_LOG("dfuRuleRelayDataTransferComplete, allowed to run");
        return rule_action_run;
    }
#endif
    DFU_RULE_LOG("dfuRuleRelayDataTransferComplete, ignore as dfu rules not allowed to run");
    return rule_action_ignore;
}

static rule_action_t dfuRuleRelayResumePointInfo(void)
{
	DFU_RULE_LOG("dfuRuleRelayResumePointInfo, allowed to run");
	return rule_action_run;
}

static rule_action_t dfuRuleStartPeerDFU(void)
{
#ifdef INCLUDE_DFU_PEER
    bool is_primary = BtDevice_IsMyAddressPrimary();
    if(Dfu_IsUpgradeInProgress() && !UPGRADE_PEER_IS_STARTED && is_primary 
       && Dfu_GetPeerSigL2capStatus() == dfu_peer_sig_l2cap_connected && !UpgradeIsSingleDeviceDFUEnabled()
       && !dfuPeer_IsHandOverDisconnectingState())
    {
        DFU_RULE_LOG("dfuRuleStartPeerDFU, allowed to run");
        return rule_action_run;
    }
#endif
    DFU_RULE_LOG("dfuRuleStartPeerDFU, ignore as dfu rules not allowed to run");
    return rule_action_ignore;
}

static rule_action_t dfuRuleStartReboot(void)
{
#ifdef INCLUDE_DFU_PEER
    bool is_primary = BtDevice_IsMyAddressPrimary();
#endif

    /* In case of earbud, for Secondary EB, just check if UPGRADE_HOST_TRANSFER_COMPLETE_RES is received */
    if (UpgradeIsTransferCompleteResponseReceived()
#ifdef INCLUDE_DFU_PEER
        && (!is_primary 
            || (UPGRADE_PEER_IS_CONNECTED && UPGRADE_PEER_IS_PRIMARY && UpgradePeerIsStateProcessComplete()
           )
        || UpgradeIsCrossVersionStatusLower() || UpgradeIsSingleDeviceDFUEnabled())
#endif
        )
    {
        DFU_RULE_LOG("dfuRuleStartReboot, allowed to run");
        return rule_action_run;
    }

    DFU_RULE_LOG("dfuRuleStartReboot, ignore as dfu rules not allowed to run");
    return rule_action_ignore;
}

#ifdef INCLUDE_DFU_PEER
static rule_action_t dfuRuleCommitPeer(void)
{
    bool is_silent_commit_enabled = Dfu_IsSilentCommitEnabled();
    bool is_primary = BtDevice_IsMyAddressPrimary();
    /*! Peer must be connected and device must be primary*/
    if( UPGRADE_PEER_IS_CONNECTED && is_primary)
    {
        if((UpgradeGetResumePoint() != UPGRADE_RESUME_POINT_POST_REBOOT 
            || UpgradePeerGetResumePoint() != UPGRADE_RESUME_POINT_POST_REBOOT))
        {
            DFU_RULE_LOG("dfuRuleCommitPeer, ignore as post reboot resume point mismatch");
            return rule_action_ignore;
        }
        /*! For interactive commit, primary should have received, COMMIT_REQ from peer,
         * and COMMIT_CFM host message from host to commit peer.*/
        if(!is_silent_commit_enabled && UpgradePeerStateIsCommitReqRcd() && UpgradeStateIsCommit())
        {
            DFU_RULE_LOG("dfuRuleCommitPeer, allows to run in interactive commit");
            return rule_action_run;
        }
        /*! For silent commit, device should have received COMMIT_REQ from peer.*/
        if(is_silent_commit_enabled && UpgradePeerStateIsCommitReqRcd())
        {
            DFU_RULE_LOG("dfuRuleCommitPeer, allows to run in silent commit");
            return rule_action_run;
        }
    }

    DFU_RULE_LOG("dfuRuleCommitPeer, ignore as dfu rules not allowed to run");
    return rule_action_ignore;
}
#endif
#ifdef INCLUDE_TRANSPORT_LAYER_RELAY
static rule_action_t dfuRuleStartTransportRelay(void)
{
    bool is_self_active_and_in_data_transfer = DfuTrasportRelayIsSelfStreamActive() && UpgradeSmIsStateDataTransfer();
    bool is_peer_active_and_in_data_transfer = DfuTrasportRelayIsPeerStreamActive() && UpgradeSmIsStateDataTransfer();

    /* Check if both upgrade and upgrade_peer libraries are in correct state to receive data and both peer and upgrade_transport is connected. */
    if(DfuPeerIsConnected() && UpgradeTransportInUse())
    {
        if(UpgradeGetResumePoint() == UPGRADE_RESUME_POINT_START && UpgradePeerGetResumePoint() == UPGRADE_PEER_RESUME_POINT_START)
        {
            /* If self and peer are in UPGRADE_RESUME_POINT_START then both need to be active */
            if(is_self_active_and_in_data_transfer && is_peer_active_and_in_data_transfer)
            {
                DFU_RULE_LOG("dfuRuleStartTransportRelay, allowed to run");
                return rule_action_run;
            }
        }
        else if(UpgradeGetResumePoint() == UPGRADE_RESUME_POINT_PRE_VALIDATE)
        {
            /* If only self is in  UPGRADE_RESUME_POINT_START then it needs to be active */
            if(is_peer_active_and_in_data_transfer)
            {
                DFU_RULE_LOG("dfuRuleStartTransportRelay, allowed to run");
                return rule_action_run;
            }
        }
        else if(UpgradePeerGetResumePoint() == UPGRADE_PEER_RESUME_POINT_PRE_VALIDATE)
        {
            /* If only peer is in  UPGRADE_RESUME_POINT_START then it needs to be active */
            if(is_self_active_and_in_data_transfer)
            {
                DFU_RULE_LOG("dfuRuleStartTransportRelay, allowed to run");
                return rule_action_run;
            }
        }
    }

    DFU_RULE_LOG("dfuRuleStartTransportRelay, ignore as dfu rules not allowed to run");
    return rule_action_ignore;
}
#endif

/* Currently there is no rule set which runs with params. Hence this code is gaurded now.
 * Will be ungaurded once there is any usage
 */
#ifdef RUN_WITH_PARAM
/*****************************************************************************
 * END RULES FUNCTIONS
 *****************************************************************************/

/*! \brief Copy rule param data for the engine to put into action messages.
    \param param Pointer to data to copy.
    \param size_param Size of the data in bytes.
    \return rule_action_run_with_param to indicate the rule action message needs parameters.
*/ 
static rule_action_t dfuRules_CopyRunParams(const void* param, size_t size_param)
{
    dfu_rules_task_data_t *dfu_rules = DfuRulesGetTaskData();
    RulesEngine_CopyRunParams(dfu_rules->rule_set, param, size_param);

    return rule_action_run_with_param;
}
#endif


/*! \brief Initialise the dfu rules module. */
bool DfuRules_Init(Task result_task)
{
    UNUSED(result_task);

    dfu_rules_task_data_t *dfu_rules = DfuRulesGetTaskData();
    rule_set_init_params_t rule_params;

    memset(&rule_params, 0, sizeof(rule_params));
    rule_params.rules = dfu_rules_set;
    rule_params.rules_count = ARRAY_DIM(dfu_rules_set);
    rule_params.nop_message_id = DFU_RULES_NOP;
    rule_params.event_task = result_task;
    dfu_rules->rule_set = RulesEngine_CreateRuleSet(&rule_params);
    return TRUE;
}

rule_set_t DfuRules_GetRuleSet(void)
{
    dfu_rules_task_data_t *dfu_rules = DfuRulesGetTaskData();
    return dfu_rules->rule_set;
}

void DfuRules_SetEvent(rule_events_t event_mask)
{
    dfu_rules_task_data_t *dfu_rules = DfuRulesGetTaskData();
    RulesEngine_SetEvent(dfu_rules->rule_set, event_mask);
}

void DfuRules_ResetEvent(rule_events_t event)
{
    dfu_rules_task_data_t *dfu_rules = DfuRulesGetTaskData();
    RulesEngine_ResetEvent(dfu_rules->rule_set, event);
}

rule_events_t DfuRules_GetEvents(void)
{
    dfu_rules_task_data_t *dfu_rules = DfuRulesGetTaskData();
    return RulesEngine_GetEvents(dfu_rules->rule_set);
}

void DfuRules_SetRuleComplete(MessageId message)
{
    dfu_rules_task_data_t *dfu_rules = DfuRulesGetTaskData();
    RulesEngine_SetRuleComplete(dfu_rules->rule_set, message);
}

void DfuRules_SetRuleWithEventComplete(MessageId message, rule_events_t event)
{
    dfu_rules_task_data_t *dfu_rules = DfuRulesGetTaskData();
    RulesEngine_SetRuleWithEventComplete(dfu_rules->rule_set, message, event);
}

#endif /* INCLUDE_DFU */
